//
// Created by Administrator on 2020/1/14.
//

#include <string>
#include <unistd.h>
#include "riru_module_demo.h"
#include "../jni_utils.h"
#include "../log_utils.h"
#include "../Hook.h"
#include "../method_utils.h"
#include "../DexManager.h"
#include "../file_utils.h"
#include "../riru.h"
#include "../classloader_utils.h"
#include "../xhook/xhook.h"

//#define RIRU_API extern "C" JNIEXPORT JNICALL

#define LOG_TAG "DemoModule"

extern "C" JNIEXPORT std::string JNICALL GetModuleName(){
    return "Demo";
}

#define DEFAULT_DEX_PATH "/data/local/tmp/Riru.dex"

#define ZYGOTE_PRELOAD_HOOK_NAME "ZygoteInit.preload"

void start_riru_java(JNIEnv *env){
    //尝试加载一个Dex
    std::string dex_path=DEFAULT_DEX_PATH;
    std::string empty_lib_path;
    empty_lib_path.clear();
    jobject dcl= DexManager::GetInstance()->NewLoader(env,"",dex_path,
                                                      DEFAULT_MODULE_PATH,empty_lib_path);
    AKLog("dcl:%p\n",dcl);
    if(!dcl){
        AKLogErr("fail to load dex:%s\n",dex_path.c_str());
        return;
    }
    //启动Riru的dex逻辑
    jclass riru_class= load_by_specific(env,dcl,
            "com.pvdnc.riru.Riru");
    AKLog("riru class:%p\n",riru_class);
    if(!riru_class){
        AKLogErr("fail to load riru_class");
        return;
    }
    jmethodID start_method=env->GetStaticMethodID(riru_class,"start","()V");
    AKLog("start_method:%p\n",start_method);
    if(!start_method){
        AKLogErr("fail to find start_method\n");
        return;
    }
    env->CallStaticVoidMethod(riru_class,start_method);
    AKTagLog("Riru java should start its work\n");
}

extern "C" void my_preload(JNIEnv *env,jclass clazz,jobject bootTimingsTraceLog){
    jmethodID old_method=Hook::GetInstance()->GetOldMethod(ZYGOTE_PRELOAD_HOOK_NAME);
    if(!old_method){
        AKLogErr("fail to get old_method\n");
        return;
    }
    env->CallStaticVoidMethod(clazz,old_method,bootTimingsTraceLog);//调用原方法
    AKLog("old preload has finished at pid:%d\n",getpid());

    start_riru_java(env);

    AKLog("finish my_preload\n");
}

extern "C" JNIEXPORT jint JNICALL OnCreateVM(JavaVM** p_vm,JNIEnv** p_env,void* reserved){
    AKTagLogErr("Demo module OnCreateVM\n");
    JNIEnv *env=*p_env;
    AKTagLog("JNIEnv:%p\n",env);
    //com.android.internal.os.ZygoteInit#preload
    jclass zygote_init_class=env->FindClass("com/android/internal/os/ZygoteInit");
    AKTagLogErr("zygote_init_class:%p\n",zygote_init_class);
    //static void preload(TimingsTraceLog bootTimingsTraceLog)-29 23没参数的
    jmethodID preload=get_method_by_name(env,zygote_init_class,"preload");
    try_catch(env, false);
    if(!preload){
        AKTagLogErr("fail to get preload method\n");
        return JNI_OK;
    }
    AKTagLog("preload:%p\n",preload);
    Hook::GetInstance()->JavaHook(env,ZYGOTE_PRELOAD_HOOK_NAME,preload,
            reinterpret_cast<void*>(my_preload));
    jmethodID old_method=Hook::GetInstance()->GetOldMethod(ZYGOTE_PRELOAD_HOOK_NAME);
    AKTagLog("preload old_method:%p\n",old_method);
    return JNI_OK;
}
